package com.centsuse.my_redis.utils;

import org.redisson.api.RMap;
import org.redisson.api.RMapCache;
import org.redisson.api.RedissonClient;
import org.redisson.client.codec.Codec;
import org.redisson.codec.JsonJacksonCodec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.Duration;
import java.time.temporal.TemporalUnit;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

/**
 * 通用的 Redisson RMap 工具类
 * 提供对 Redis Hash 数据结构的操作封装
 *
 * @param <K> 键的类型
 * @param <V> 值的类型
 */
@Component
public class RedissonMapUtil<K, V> {

    private static final Logger logger = LoggerFactory.getLogger(RedissonMapUtil.class);

    @Autowired
    private RedissonClient redissonClient;

    // 默认使用 JSON 序列化编解码器
    private final Codec codec = new JsonJacksonCodec();

    /**
     * 获取指定名称的 RMap 对象
     *
     * @param mapName Map 的名称
     * @return RMap 对象
     */
    public RMap<K, V> getMap(String mapName) {
        return redissonClient.getMap(mapName, codec);
    }

    /**
     * 获取指定名称的 RMapCache 对象（支持过期时间）
     *
     * @param mapName Map 的名称
     * @return RMapCache 对象
     */
    public RMapCache<K, V> getMapCache(String mapName) {
        return redissonClient.getMapCache(mapName, codec);
    }

    /**
     * 向指定 Map 中添加键值对
     *
     * @param mapName Map 的名称
     * @param key     键
     * @param value   值
     * @return 之前与键关联的值（如果有）
     */
    public V put(String mapName, K key, V value) {
        try {
            RMap<K, V> map = getMap(mapName);
            return map.put(key, value);
        } catch (Exception e) {
            logger.error("Error putting value into map: {}", mapName, e);
            return null;
        }
    }

    /**
     * 向指定 Map 中添加键值对，并为整个 Map 设置过期时间
     *
     * @param mapName  Map 的名称
     * @param key      键
     * @param value    值
     * @param ttl      过期时间
     * @param timeUnit 时间单位
     * @return 之前与键关联的值（如果有）
     */
    public V putWithTTL(String mapName, K key, V value, long ttl, TimeUnit timeUnit) {
        try {
            RMapCache<K, V> mapCache = getMapCache(mapName);
            return mapCache.put(key, value, ttl, timeUnit);
        } catch (Exception e) {
            logger.error("Error putting value into map with TTL: {}", mapName, e);
            return null;
        }
    }

    /**
     * 仅当键不存在时向指定 Map 中添加键值对
     *
     * @param mapName Map 的名称
     * @param key     键
     * @param value   值
     * @return 如果键已存在返回 null，否则返回新值
     */
    public V putIfAbsent(String mapName, K key, V value) {
        try {
            RMap<K, V> map = getMap(mapName);
            return map.putIfAbsent(key, value);
        } catch (Exception e) {
            logger.error("Error putting value if absent into map: {}", mapName, e);
            return null;
        }
    }

    /**
     * 从指定 Map 中获取指定键的值
     *
     * @param mapName Map 的名称
     * @param key     键
     * @return 与键关联的值，如果不存在返回 null
     */
    public V get(String mapName, K key) {
        try {
            RMap<K, V> map = getMap(mapName);
            return map.get(key);
        } catch (Exception e) {
            logger.error("Error getting value from map: {}", mapName, e);
            return null;
        }
    }

    /**
     * 从指定 Map 中获取所有键
     *
     * @param mapName Map 的名称
     * @return 包含所有键的 Set
     */
    public Set<K> getAllKeys(String mapName) {
        try {
            RMap<K, V> map = getMap(mapName);
            return map.readAllKeySet();
        } catch (Exception e) {
            logger.error("Error getting all keys from map: {}", mapName, e);
            return Collections.emptySet();
        }
    }

    /**
     * 从指定 Map 中获取所有值
     *
     * @param mapName Map 的名称
     * @return 包含所有值的 Collection
     */
    public Collection<V> getAllValues(String mapName) {
        try {
            RMap<K, V> map = getMap(mapName);
            return map.readAllValues();
        } catch (Exception e) {
            logger.error("Error getting all values from map: {}", mapName, e);
            return Collections.emptyList();
        }
    }

    /**
     * 从指定 Map 中获取所有键值对
     *
     * @param mapName Map 的名称
     * @return 包含所有键值对的 Map
     */
    public Map<K, V> getAllEntries(String mapName) {
        try {
            RMap<K, V> map = getMap(mapName);
            return map.readAllMap();
        } catch (Exception e) {
            logger.error("Error getting all entries from map: {}", mapName, e);
            return Collections.emptyMap();
        }
    }

    /**
     * 检查指定 Map 中是否包含指定键
     *
     * @param mapName Map 的名称
     * @param key     键
     * @return 如果包含返回 true，否则返回 false
     */
    public boolean containsKey(String mapName, K key) {
        try {
            RMap<K, V> map = getMap(mapName);
            return map.containsKey(key);
        } catch (Exception e) {
            logger.error("Error checking key in map: {}", mapName, e);
            return false;
        }
    }

    /**
     * 从指定 Map 中移除指定键
     *
     * @param mapName Map 的名称
     * @param key     键
     * @return 被移除的值，如果键不存在返回 null
     */
    public V remove(String mapName, K key) {
        try {
            RMap<K, V> map = getMap(mapName);
            return map.remove(key);
        } catch (Exception e) {
            logger.error("Error removing key from map: {}", mapName, e);
            return null;
        }
    }

    /**
     * 获取指定 Map 的大小
     *
     * @param mapName Map 的名称
     * @return Map 中键值对的数量
     */
    public long size(String mapName) {
        try {
            RMap<K, V> map = getMap(mapName);
            return map.size();
        } catch (Exception e) {
            logger.error("Error getting size of map: {}", mapName, e);
            return 0;
        }
    }

    /**
     * 清空指定 Map
     *
     * @param mapName Map 的名称
     */
    public void clear(String mapName) {
        try {
            RMap<K, V> map = getMap(mapName);
            map.clear();
        } catch (Exception e) {
            logger.error("Error clearing map: {}", mapName, e);
        }
    }

    /**
     * 删除指定 Map
     *
     * @param mapName Map 的名称
     */
    public void delete(String mapName) {
        try {
            RMap<K, V> map = getMap(mapName);
            map.delete();
        } catch (Exception e) {
            logger.error("Error deleting map: {}", mapName, e);
        }
    }

    /**
     * 批量向指定 Map 中添加键值对
     *
     * @param mapName Map 的名称
     * @param map     包含要添加的键值对的 Map
     */
    public void putAll(String mapName, Map<? extends K, ? extends V> map) {
        try {
            RMap<K, V> rMap = getMap(mapName);
            rMap.putAll(map);
        } catch (Exception e) {
            logger.error("Error putting all values into map: {}", mapName, e);
        }
    }

    /**
     * 批量从指定 Map 中获取值
     *
     * @param mapName Map 的名称
     * @param keys    要获取的键的集合
     * @return 包含键值对的 Map
     */
    public Map<K, V> getAll(String mapName, Set<K> keys) {
        try {
            RMap<K, V> rMap = getMap(mapName);
            return rMap.getAll(keys);
        } catch (Exception e) {
            logger.error("Error getting values from map: {}", mapName, e);
            return Collections.emptyMap();
        }
    }

    /**
     * 为指定 Map 中的指定键设置过期时间
     *
     * @param mapName  Map 的名称
     * @param key      键
     * @param ttl      过期时间
     * @param timeUnit 时间单位
     * @return 如果设置成功返回 true，否则返回 false
     */
    public V putWithExpire(String mapName, K key, V value, long ttl, TimeUnit timeUnit) {
        try {
            RMapCache<K, V> mapCache = getMapCache(mapName);
            return mapCache.put(key, value, ttl, timeUnit);
        } catch (Exception e) {
            logger.error("Error putting value with expire: {}", mapName, e);
            return null;
        }
    }

    /**
     * 为整个 Map 设置过期时间
     *
     * @param mapName  Map 的名称
     * @param ttl      过期时间
     * @param timeUnit 时间单位
     * @return 如果设置成功返回 true，否则返回 false
     */
    public boolean expireMap(String mapName, long ttl, TemporalUnit timeUnit) {
        try {
            RMap<K, V> map = getMap(mapName);
            return map.expire(Duration.of(ttl, timeUnit));
        } catch (Exception e) {
            logger.error("Error setting expire for map: {}", mapName, e);
            return false;
        }
    }
}
